﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using agree.schema;

using alib;
using alib.Collections;
using alib.Debugging;
using alib.Enumerable;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public sealed class GenericLexicalEntry : StaticExpandEntry, ILexeme
	{
		public GenericLexicalEntry(Grammar g, Type t, ConsDefs consdef)
			: base(g, t, consdef)
		{
		}

		///////////////////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public ITokenizer Tokenizer
		{
			get { return em.lex.Tokenizer ?? em.DefaultTokenizer ?? SplitTokenizer.SpaceCharTokenizer; }
			set { throw not.valid; }
		}
		/// 
		///////////////////////////////////////////////////////////////////////

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int DaughterArity { get { return 0; } }

		String ref_form;
		public String ReferenceForm { get { return ref_form ?? "(generic-le)"; } }

		public String ReadbackTokensForm(ITfsSlot ts)
		{
			return tmg.ReadbackTokensForm(ts, this) ?? ReferenceForm;
		}

		TfsSlot toks;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TfsSlot TfsSlotTokens
		{
			get
			{
				if (!IsExpanded)
					Expanded.touch();
				return toks;
			}
		}

		protected override Tfs EnsureExpanded()
		{
			var _exp = base.EnsureExpanded();

			TfsSlot ts1;
			if ((ts1 = _exp[ftm.im.OrthPath]).IsValid)
			{
				String s = tu.GetStringValue(ts1.FlagsId);
				if (s != null)
					ref_form = s;
				else
				{
					var rgw = ts1.ListSlots;
					if (rgw.Length != 1)
						throw new Exception();

					ref_form = rgw[0].StringValue;
				}
			}

			this.toks = _exp[tmg.LexiconTokensPath];
			if (toks.ListLength != 1)
				throw new Exception("multi-token generic lexical entry not allowed.");

			return _exp;
		}

		public override String ToString()
		{
			return String.Format("{0} {1} {2}", Name.PadRight(20), InstanceType.Name.PadRight(20), ReferenceForm);
		}
	};


#if false
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class LookupGenericLEs : identity_node,
		ρρEntryMgr,
		ρρTfsUnifier
	{
		public LookupGenericLEs(IRtParent parent, Lexicon lex, TfsUnifier unifier, FsPath toksPath)
			: base(parent, lex)
		{
			this.lex = lex;
			this.u = unifier;
			this.toksPath = toksPath;
		}

		///////////////////////////////////////////////////////////////////////
		///
		Lexicon lex;
		public Lexicon Lexicon
		{
			get { return lex; }
			set { lex = value; }
		}
		///
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		///
		TfsUnifier u;
		public TfsUnifier TfsUnifier
		{
			get { return this.u; }
			set { this.u = value; }
		}
		///
		///////////////////////////////////////////////////////////////////////

		FsPath toksPath;

		public IEnumerable<IChartObj<ChartSpan>> LookupForToken(MappingToken tok)
		{
			foreach (var gle in lex.GenericLexicalEntries)
			{
				var unify_result = UnifyTokenIntoLE(gle, new MappingToken[] { tok });
				if (unify_result != null)
				{
					var le = new lexent_itok(this, gle, tok.TokenSpan, unify_result);

					yield return le;
				}
			}
		}

		protected ArrayTfs UnifyTokenIntoLE(GenericLexicalEntry gle, MappingToken[] toks)
		{
			TfsSlot ts_list;

			toksPath.GetSlot(gle.Expanded, Tfs.TopmostMark, out ts_list);
			var gle_tok_slots = gle.Expanded.GetListSlots(ts_list.SlotIndex);

			if (toks.Length != gle_tok_slots.Length)
				return null;

			Pairing<ITfsSlot>[] pairings = new Pairing<ITfsSlot>[toks.Length];
			for (int i = 0; i < gle_tok_slots.Length; i++)
			{
				pairings[i] = new Pairing<ITfsSlot>(gle_tok_slots[i], toks[i]);
			}

			return Unification.UnifySectionsIntoShell(em.ftm.r_none, Tfs.Flags.None, pairings);
		}
	};
#endif
}
